    .code16
    .section ".text", "ax"
    .global    pmjump, lmjump
pmjump: # eax=gdtptr bx=cspm cx=cslm dx=ds
    cli
    lgdtl   (%eax)
    lidtl   (nullidt)
    movw    %bx, sgpm
    movw    %cx, sglm

    # set PAE
    movl    %cr4, %eax
    orl     $0x20, %eax
    movl    %eax, %cr4

    # set EFER.LME
    pushl   %edx
    pushl   %ecx
    movl    $0xc0000080, %ecx
    rdmsr
    orl     $0x100,    %eax
    wrmsr
    popl    %ecx
    popl    %edx

    movl    %cr4, %eax
    orl     $0x00000300, %eax   # set $cr4.OSFXSR, $cr4.OSXMMEXCPT
    movl    %eax, %cr4
    movl    %cr0, %eax
    andl    $0xfffffffb, %eax   # clear $cr0.EM
    orl     $0x80000003, %eax   # set $cr0.PG, $cr0.MP, $cr0.PM
    movl    %eax, %cr0
    .byte   0x66, 0xea  # ljmpl opcode
    .long   _pmstart    # offset
sgpm:.word  0           # segment

nullidt:
    .word   0
    .long   0

    .code32
    .section ".text", "ax"
_pmstart:
    movl    %edx, %ds
    movl    %edx, %es
    movl    %edx, %fs
    movl    %edx, %gs
    movl    %edx, %ss
    movl    $0x7bff, %eax
    movl    %eax, %ebp
    movl    %eax, %esp
    jmp     PM_Main

lmjump:
    .byte   0xea        # ljmpl opcode
    .long   _knstart      # offset
sglm:.word  0           # segment

    .code64
    .section ".text", "ax"
_knstart:
    movl    %eax, -8(%rsp)
    movl    %edx, -4(%rsp)
    movq    -8(%rsp), %rax
    movq    $0x80000-1, %rsp
    callq   *%rax
